﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.ObjectModel;
using HalconDotNet;
using Uc_Halcon.Models;
using Emgu.CV;
using Emgu.CV.Util;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using System.Windows;
using MathFlowLib.FeatureJudge;

namespace MathFlowLib
{
    /// <summary>
    /// 直线算法
    /// </summary>
    public class Vm_MathFlow_Line : Vm_MathFlow_Base<Vm_MathFlow_Line_Param,
        Vm_MathFlow_Line_Output>
    {
        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="param">算法参数</param>
        public Vm_MathFlow_Line(Vm_MathFlow_Line_Param param)
            : base(param)
        {

        }

        /// <summary>
        /// 代号
        /// </summary>
        public override string CodeName => "Line";

        /// <summary>
        /// 初始化方法
        /// </summary>
        public override void Vir_Init()
        {
            //添加检测指标
            string[] nameArr = new string[] { "角度", "均匀度", "直线度" };
            for (int i = 0; i < 3; i++)
            {
                mFeatureList.Add(new Vm_Feature()
                {
                    FeatureName = nameArr[i]
                });
            }

            //特征标准实例化
            //Param.MathFlow_FeatureStd = new Vm_MathFlow_Line_FeatureStd();

            //读取畸变校正参数Map.hobj
            //string currentPath = Environment.CurrentDirectory;
            //string mapFilePath = currentPath + @"\Map.hobj";
            //HOperatorSet.ReadObject(out hoMap, mapFilePath);


        }

        /// <summary>
        /// 算法运行方法
        /// </summary>
        public override void Vir_Run(Vm_MathFlow_Line_Output output)
        {
            //畸变校正
            HObject hoImage = Convert_HalconOpencv.ConvertSkin(output.MatImage);
            //HOperatorSet.MapImage(hoImage, hoMap, out hoImage);

            //重新赋值output.MatImage
            output.MatImage = Convert_HalconOpencv.ConvertSkin(hoImage);

            //提取线激光区域
            HObject hoLineRegion;
            cal_line_region(hoImage, out hoLineRegion);

            //计算激光线角度
            if (Param.IsCalAngle.Value)
            {
                HTuple hvAngle;
                cal_line_region_angle(hoLineRegion, out hvAngle);

                //更新结果列表
                mFeatureList[0].Value = hvAngle.D;
            }

            //计算激光线指标
            if (Param.IsCalIndicator.Value)
            {
                HTuple hvUniformity, hvStraightness, hvIntensityVals, hvDiffVals, hvWidthVals;
                cal_line_indicator(hoLineRegion, hoImage, Param.PixelSize.Value,
                    Param.FilmDistance.Value, Param.Fov.Value, out hvWidthVals,
                    out hvIntensityVals, out hvDiffVals, out hvUniformity, out hvStraightness);

                //获取强度图表数据
                Point[] intensityArr = new Point[hvIntensityVals.Length];
                for (int i = 0; i < intensityArr.Length; i++)
                {
                    intensityArr[i] = new Point(i, hvIntensityVals.TupleSelect(i));
                }

                //获取偏差图表数据
                Point[] diffArr = new Point[hvDiffVals.Length];
                for (int i = 0; i < diffArr.Length; i++)
                {
                    diffArr[i] = new Point(i, hvDiffVals.TupleSelect(i));
                }

                //获取宽度图表数据
                Point[] widthArr = new Point[hvWidthVals.Length];
                for (int i = 0; i < widthArr.Length; i++)
                {
                    widthArr[i] = new Point(i, hvWidthVals.TupleSelect(i));
                }

                //更新结果列表
                mFeatureList[1].Value = hvUniformity.D;
                mFeatureList[2].Value = hvStraightness.D;

                //更新UI
                Application.Current.Dispatcher.Invoke(() =>
                {
                    output.CurveIntensity.Points = intensityArr;
                    output.Uniformity.Value = hvUniformity.D;

                    output.CurveDiff.Points = diffArr;
                    output.Straightness.Value = hvDiffVals.D;

                    output.CurveWidth.Points = widthArr;
                });
            }

            //评价判级
            Judge();

            //结果输出
            Application.Current.Dispatcher.Invoke(() =>
            {
                for (int i = 0; i < mFeatureList.Count; i++)
                {
                    output.FeatureCollection[i].FeatureName = mFeatureList[i].FeatureName;
                    output.FeatureCollection[i].Value = mFeatureList[i].Value;
                    output.FeatureCollection[i].Bin = mFeatureList[i].Bin;
                }
            });
        }

        /// <summary>
        /// 评价判级
        /// </summary>
        private void Judge()
        {
            foreach (var item in mFeatureList)
            {
                item.Judge(Param.MathFlow_FeatureStd.FeatureStdCollection.ToList<Vm_Feature_Std>());
            }
        }

        /// <summary>
        /// 特征列表
        /// </summary>
        private List<Vm_Feature> mFeatureList = new List<Vm_Feature>();

        #region Halcon Methods

        public void min_max_region(HObject ho_inRegions, out HObject ho_minRegion, out HObject ho_maxRegion)
        {



            // Local iconic variables 

            HObject ho_ConnectedRegions;

            // Local control variables 

            HTuple hv_Area = new HTuple(), hv_Row = new HTuple();
            HTuple hv_Column = new HTuple(), hv_Indices = new HTuple();
            // Initialize local and output iconic variables 
            HOperatorSet.GenEmptyObj(out ho_minRegion);
            HOperatorSet.GenEmptyObj(out ho_maxRegion);
            HOperatorSet.GenEmptyObj(out ho_ConnectedRegions);
            try
            {
                ho_ConnectedRegions.Dispose();
                HOperatorSet.Connection(ho_inRegions, out ho_ConnectedRegions);
                hv_Area.Dispose(); hv_Row.Dispose(); hv_Column.Dispose();
                HOperatorSet.AreaCenter(ho_ConnectedRegions, out hv_Area, out hv_Row, out hv_Column);
                hv_Indices.Dispose();
                HOperatorSet.TupleSortIndex(hv_Area, out hv_Indices);
                using (HDevDisposeHelper dh = new HDevDisposeHelper())
                {
                    ho_minRegion.Dispose();
                    HOperatorSet.SelectObj(ho_ConnectedRegions, out ho_minRegion, (hv_Indices.TupleSelect(
                        0)) + 1);
                }
                using (HDevDisposeHelper dh = new HDevDisposeHelper())
                {
                    ho_maxRegion.Dispose();
                    HOperatorSet.SelectObj(ho_ConnectedRegions, out ho_maxRegion, (hv_Indices.TupleSelect(
                        (new HTuple(hv_Indices.TupleLength())) - 1)) + 1);
                }
                ho_ConnectedRegions.Dispose();

                hv_Area.Dispose();
                hv_Row.Dispose();
                hv_Column.Dispose();
                hv_Indices.Dispose();

                return;
            }
            catch (HalconException HDevExpDefaultException)
            {
                ho_ConnectedRegions.Dispose();

                hv_Area.Dispose();
                hv_Row.Dispose();
                hv_Column.Dispose();
                hv_Indices.Dispose();

                throw HDevExpDefaultException;
            }
        }

        public void cal_line_indicator(HObject ho_Region, HObject ho_Image, HTuple hv_pixel_size,
            HTuple hv_distance, HTuple hv_fov, out HTuple hv_widthVals, out HTuple hv_IntensityVals,
            out HTuple hv_diffs, out HTuple hv_Uniformity, out HTuple hv_Straightness)
        {




            // Local iconic variables 

            HObject ho_rect = null, ho_subImage = null, ho_reg = null;

            // Local control variables 

            HTuple hv_distance_pix = new HTuple(), hv_line_length = new HTuple();
            HTuple hv_null = new HTuple(), hv_rowCenter = new HTuple();
            HTuple hv_colCenter = new HTuple(), hv_colStart = new HTuple();
            HTuple hv_colEnd = new HTuple(), hv_rowVals = new HTuple();
            HTuple hv_i = new HTuple(), hv_maxVal = new HTuple(), hv_thresVal = new HTuple();
            HTuple hv_widthVal = new HTuple(), hv_rowVal = new HTuple();
            HTuple hv_rowMean = new HTuple(), hv_intensityMax = new HTuple();
            HTuple hv_intensityMin = new HTuple(), hv_diffMax = new HTuple();
            HTuple hv_diffMin = new HTuple();
            // Initialize local and output iconic variables 
            HOperatorSet.GenEmptyObj(out ho_rect);
            HOperatorSet.GenEmptyObj(out ho_subImage);
            HOperatorSet.GenEmptyObj(out ho_reg);
            hv_widthVals = new HTuple();
            hv_IntensityVals = new HTuple();
            hv_diffs = new HTuple();
            hv_Uniformity = new HTuple();
            hv_Straightness = new HTuple();
            try
            {
                //计算得到参数
                hv_distance_pix.Dispose();
                using (HDevDisposeHelper dh = new HDevDisposeHelper())
                {
                    hv_distance_pix = hv_distance / hv_pixel_size;
                }
                hv_line_length.Dispose();
                using (HDevDisposeHelper dh = new HDevDisposeHelper())
                {
                    hv_line_length = ((2 * hv_distance_pix) * (((((hv_fov / 2.0)).TupleRad()
                        )).TupleTan())) * 0.8;
                }

                //计算中心点位置
                hv_null.Dispose(); hv_rowCenter.Dispose(); hv_colCenter.Dispose();
                HOperatorSet.AreaCenter(ho_Region, out hv_null, out hv_rowCenter, out hv_colCenter);

                //计算线长范围
                hv_colStart.Dispose();
                using (HDevDisposeHelper dh = new HDevDisposeHelper())
                {
                    hv_colStart = hv_colCenter - (hv_line_length / 2);
                }
                hv_colEnd.Dispose();
                using (HDevDisposeHelper dh = new HDevDisposeHelper())
                {
                    hv_colEnd = hv_colCenter + (hv_line_length / 2);
                }

                //获取曲线数据
                hv_widthVals.Dispose();
                hv_widthVals = new HTuple();
                hv_IntensityVals.Dispose();
                hv_IntensityVals = new HTuple();
                hv_rowVals.Dispose();
                hv_rowVals = new HTuple();
                HTuple end_val15 = hv_colEnd;
                HTuple step_val15 = 1;
                for (hv_i = hv_colStart; hv_i.Continue(end_val15, step_val15); hv_i = hv_i.TupleAdd(step_val15))
                {
                    using (HDevDisposeHelper dh = new HDevDisposeHelper())
                    {
                        ho_rect.Dispose();
                        HOperatorSet.GenRectangle1(out ho_rect, hv_rowCenter - 50, hv_i, hv_rowCenter + 50,
                            hv_i);
                    }

                    hv_maxVal.Dispose();
                    HOperatorSet.GrayFeatures(ho_rect, ho_Image, "max", out hv_maxVal);
                    hv_thresVal.Dispose();
                    using (HDevDisposeHelper dh = new HDevDisposeHelper())
                    {
                        hv_thresVal = 0.135 * hv_maxVal;
                    }
                    ho_subImage.Dispose();
                    HOperatorSet.ReduceDomain(ho_Image, ho_rect, out ho_subImage);
                    ho_reg.Dispose();
                    HOperatorSet.Threshold(ho_subImage, out ho_reg, hv_thresVal, 255);

                    hv_widthVal.Dispose();
                    HOperatorSet.RegionFeatures(ho_reg, "area", out hv_widthVal);
                    hv_rowVal.Dispose();
                    HOperatorSet.GrayFeatures(ho_reg, ho_Image, "row", out hv_rowVal);

                    using (HDevDisposeHelper dh = new HDevDisposeHelper())
                    {
                        {
                            HTuple
                              ExpTmpLocalVar_widthVals = hv_widthVals.TupleConcat(
                                hv_widthVal);
                            hv_widthVals.Dispose();
                            hv_widthVals = ExpTmpLocalVar_widthVals;
                        }
                    }
                    using (HDevDisposeHelper dh = new HDevDisposeHelper())
                    {
                        {
                            HTuple
                              ExpTmpLocalVar_IntensityVals = hv_IntensityVals.TupleConcat(
                                hv_maxVal);
                            hv_IntensityVals.Dispose();
                            hv_IntensityVals = ExpTmpLocalVar_IntensityVals;
                        }
                    }
                    using (HDevDisposeHelper dh = new HDevDisposeHelper())
                    {
                        {
                            HTuple
                              ExpTmpLocalVar_rowVals = hv_rowVals.TupleConcat(
                                hv_rowVal);
                            hv_rowVals.Dispose();
                            hv_rowVals = ExpTmpLocalVar_rowVals;
                        }
                    }

                    //stop ()
                }
                hv_rowMean.Dispose();
                HOperatorSet.TupleMean(hv_rowVals, out hv_rowMean);
                hv_diffs.Dispose();
                using (HDevDisposeHelper dh = new HDevDisposeHelper())
                {
                    hv_diffs = hv_rowMean - hv_rowVals;
                }

                //像素转换为物理尺寸
                using (HDevDisposeHelper dh = new HDevDisposeHelper())
                {
                    {
                        HTuple
                          ExpTmpLocalVar_widthVals = hv_widthVals * hv_pixel_size;
                        hv_widthVals.Dispose();
                        hv_widthVals = ExpTmpLocalVar_widthVals;
                    }
                }
                using (HDevDisposeHelper dh = new HDevDisposeHelper())
                {
                    {
                        HTuple
                          ExpTmpLocalVar_diffs = hv_diffs * hv_pixel_size;
                        hv_diffs.Dispose();
                        hv_diffs = ExpTmpLocalVar_diffs;
                    }
                }

                //计算均匀度
                hv_intensityMax.Dispose();
                HOperatorSet.TupleMax(hv_IntensityVals, out hv_intensityMax);
                hv_intensityMin.Dispose();
                HOperatorSet.TupleMin(hv_IntensityVals, out hv_intensityMin);
                hv_Uniformity.Dispose();
                using (HDevDisposeHelper dh = new HDevDisposeHelper())
                {
                    hv_Uniformity = (hv_intensityMax - hv_intensityMin) / (hv_intensityMax + hv_intensityMin);
                }

                //计算直线度
                hv_diffMax.Dispose();
                HOperatorSet.TupleMax(hv_diffs, out hv_diffMax);
                hv_diffMin.Dispose();
                HOperatorSet.TupleMin(hv_diffs, out hv_diffMin);
                hv_Straightness.Dispose();
                using (HDevDisposeHelper dh = new HDevDisposeHelper())
                {
                    hv_Straightness = (hv_diffMax - hv_diffMin) / (hv_line_length * hv_pixel_size);
                }
                ho_rect.Dispose();
                ho_subImage.Dispose();
                ho_reg.Dispose();

                hv_distance_pix.Dispose();
                hv_line_length.Dispose();
                hv_null.Dispose();
                hv_rowCenter.Dispose();
                hv_colCenter.Dispose();
                hv_colStart.Dispose();
                hv_colEnd.Dispose();
                hv_rowVals.Dispose();
                hv_i.Dispose();
                hv_maxVal.Dispose();
                hv_thresVal.Dispose();
                hv_widthVal.Dispose();
                hv_rowVal.Dispose();
                hv_rowMean.Dispose();
                hv_intensityMax.Dispose();
                hv_intensityMin.Dispose();
                hv_diffMax.Dispose();
                hv_diffMin.Dispose();

                return;
            }
            catch (HalconException HDevExpDefaultException)
            {
                ho_rect.Dispose();
                ho_subImage.Dispose();
                ho_reg.Dispose();

                hv_distance_pix.Dispose();
                hv_line_length.Dispose();
                hv_null.Dispose();
                hv_rowCenter.Dispose();
                hv_colCenter.Dispose();
                hv_colStart.Dispose();
                hv_colEnd.Dispose();
                hv_rowVals.Dispose();
                hv_i.Dispose();
                hv_maxVal.Dispose();
                hv_thresVal.Dispose();
                hv_widthVal.Dispose();
                hv_rowVal.Dispose();
                hv_rowMean.Dispose();
                hv_intensityMax.Dispose();
                hv_intensityMin.Dispose();
                hv_diffMax.Dispose();
                hv_diffMin.Dispose();

                throw HDevExpDefaultException;
            }
        }

        public void cal_line_region(HObject ho_Image, out HObject ho_Region)
        {



            // Stack for temporary objects 
            HObject[] OTemp = new HObject[20];

            // Local iconic variables 

            HObject ho_ImageOut = null, ho_ImageMean, ho_minRegion;
            // Initialize local and output iconic variables 
            HOperatorSet.GenEmptyObj(out ho_Region);
            HOperatorSet.GenEmptyObj(out ho_ImageOut);
            HOperatorSet.GenEmptyObj(out ho_ImageMean);
            HOperatorSet.GenEmptyObj(out ho_minRegion);
            try
            {
                ho_ImageOut.Dispose();
                ho_ImageOut = new HObject(ho_Image);
                //预处理
                {
                    HObject ExpTmpOutVar_0;
                    HOperatorSet.MeanImage(ho_ImageOut, out ExpTmpOutVar_0, 9, 9);
                    ho_ImageOut.Dispose();
                    ho_ImageOut = ExpTmpOutVar_0;
                }

                //提取图案
                ho_ImageMean.Dispose();
                HOperatorSet.MeanImage(ho_ImageOut, out ho_ImageMean, 20, 20);
                ho_Region.Dispose();
                HOperatorSet.DynThreshold(ho_ImageOut, ho_ImageMean, out ho_Region, 10, "light");
                ho_minRegion.Dispose();
                {
                    HObject ExpTmpOutVar_0;
                    min_max_region(ho_Region, out ho_minRegion, out ExpTmpOutVar_0);
                    ho_Region.Dispose();
                    ho_Region = ExpTmpOutVar_0;
                }
                ho_ImageOut.Dispose();
                ho_ImageMean.Dispose();
                ho_minRegion.Dispose();


                return;
            }
            catch (HalconException HDevExpDefaultException)
            {
                ho_ImageOut.Dispose();
                ho_ImageMean.Dispose();
                ho_minRegion.Dispose();


                throw HDevExpDefaultException;
            }
        }

        public void cal_line_region_angle(HObject ho_Region, out HTuple hv_Deg)
        {



            // Local iconic variables 

            HObject ho_Skeleton, ho_Contours, ho_UnionContours;
            HObject ho_maxContour;

            // Local control variables 

            HTuple hv_Phi = new HTuple();
            // Initialize local and output iconic variables 
            HOperatorSet.GenEmptyObj(out ho_Skeleton);
            HOperatorSet.GenEmptyObj(out ho_Contours);
            HOperatorSet.GenEmptyObj(out ho_UnionContours);
            HOperatorSet.GenEmptyObj(out ho_maxContour);
            hv_Deg = new HTuple();
            try
            {
                //计算角度
                ho_Skeleton.Dispose();
                HOperatorSet.Skeleton(ho_Region, out ho_Skeleton);
                ho_Contours.Dispose();
                HOperatorSet.GenContoursSkeletonXld(ho_Skeleton, out ho_Contours, 1, "filter");
                ho_UnionContours.Dispose();
                HOperatorSet.UnionAdjacentContoursXld(ho_Contours, out ho_UnionContours, 10,
                    1, "attr_keep");
                ho_maxContour.Dispose();
                max_contour(ho_UnionContours, out ho_maxContour);
                hv_Phi.Dispose();
                HOperatorSet.OrientationXld(ho_maxContour, out hv_Phi);
                hv_Deg.Dispose();
                HOperatorSet.TupleDeg(hv_Phi, out hv_Deg);
                if ((int)(new HTuple(hv_Deg.TupleLess(-90))) != 0)
                {
                    using (HDevDisposeHelper dh = new HDevDisposeHelper())
                    {
                        {
                            HTuple
                              ExpTmpLocalVar_Deg = hv_Deg + 180;
                            hv_Deg.Dispose();
                            hv_Deg = ExpTmpLocalVar_Deg;
                        }
                    }
                }
                else if ((int)(new HTuple(hv_Deg.TupleGreater(90))) != 0)
                {
                    using (HDevDisposeHelper dh = new HDevDisposeHelper())
                    {
                        {
                            HTuple
                              ExpTmpLocalVar_Deg = hv_Deg - 180;
                            hv_Deg.Dispose();
                            hv_Deg = ExpTmpLocalVar_Deg;
                        }
                    }
                }
                ho_Skeleton.Dispose();
                ho_Contours.Dispose();
                ho_UnionContours.Dispose();
                ho_maxContour.Dispose();

                hv_Phi.Dispose();

                return;
            }
            catch (HalconException HDevExpDefaultException)
            {
                ho_Skeleton.Dispose();
                ho_Contours.Dispose();
                ho_UnionContours.Dispose();
                ho_maxContour.Dispose();

                hv_Phi.Dispose();

                throw HDevExpDefaultException;
            }
        }

        public void max_contour(HObject ho_UnionContours, out HObject ho_maxContour)
        {



            // Local control variables 

            HTuple hv_Length = new HTuple(), hv_Indices = new HTuple();
            // Initialize local and output iconic variables 
            HOperatorSet.GenEmptyObj(out ho_maxContour);
            try
            {
                hv_Length.Dispose();
                HOperatorSet.LengthXld(ho_UnionContours, out hv_Length);
                hv_Indices.Dispose();
                HOperatorSet.TupleSortIndex(hv_Length, out hv_Indices);
                using (HDevDisposeHelper dh = new HDevDisposeHelper())
                {
                    ho_maxContour.Dispose();
                    HOperatorSet.SelectObj(ho_UnionContours, out ho_maxContour, 1 + (hv_Indices.TupleSelect(
                        (new HTuple(hv_Indices.TupleLength())) - 1)));
                }

                hv_Length.Dispose();
                hv_Indices.Dispose();

                return;
            }
            catch (HalconException HDevExpDefaultException)
            {

                hv_Length.Dispose();
                hv_Indices.Dispose();

                throw HDevExpDefaultException;
            }
        }

        #endregion

        #region Private

        HObject hoMap;

        #endregion
    }

}
